
/***********************************************************************************************************************
**                                                    Includes                                                        **
***********************************************************************************************************************/
#include "I2c.h" 

/***********************************************************************************************************************
**                                           Global Variable Definitions                                              **
***********************************************************************************************************************/


/***********************************************************************************************************************
**                                            Private Macro Definitions                                               **
***********************************************************************************************************************/
#define I2C_SHORT_TIMEOUT   (0x2FFu)
#define I2C_LONG_TIMEOUT    (0x4FFFu)

/***********************************************************************************************************************
**                                            Private Type Definitions                                                **
***********************************************************************************************************************/

/***********************************************************************************************************************
**                                           Private Variable Definitions                                             **
***********************************************************************************************************************/


/***********************************************************************************************************************
**                                           Private Function Declarations                                            **
***********************************************************************************************************************/
static void I2C_Delay(uint32 i);
static void I2C_Resume(uint32 I2Cx, uint32 Timeout);
static void I2C_Init(uint32 I2Cx);
static Std_ReturnType I2C_WaitFlag(uint32 i2c_periph, i2c_flag_enum flag, FlagStatus matchFlag);

/***********************************************************************************************************************
**                                            Global Function Definitions                                             **
***********************************************************************************************************************/
void I2C_DriverInit(void)
{
    I2C_Init(I2C0);
    //I2C_Init(I2C1);
}

/*
    \brief      I2Cx Read NBytes 
    \param[in]  i2c_periph  : I2Cx(x=0,1)
    \param[in]  driver Addr : slave address   
    \param[in]  start_Addr  : reg
    \param[in]  number_Bytes: number to read
    \param[out] read_Buffer 
    \param[in]  ADDR_Length : number of the addr
*/
Std_ReturnType I2C_Read_NBytes(uint32 I2Cx, uint8 driver_Addr, uint16 start_Addr, uint8 number_Bytes, uint8 *read_Buffer, uint8 ADDR_Length)
{
    uint32 timeout;
    uint32 rcvTimeout = I2C_LONG_TIMEOUT;
    Std_ReturnType ret = E_OK;
    
    i2c_ack_config(I2Cx,I2C_ACK_ENABLE);	
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_I2CBSY, RESET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }
    if (2u == number_Bytes)
	{
        i2c_ackpos_config(I2Cx, I2C_ACKPOS_NEXT);
    }
	
    i2c_start_on_bus(I2Cx);
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_SBSEND, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }

	i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER);
	ret = I2C_WaitFlag(I2Cx, I2C_FLAG_ADDSEND, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(I2Cx, I2C_FLAG_ADDSEND);
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_TBE, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }
    i2c_enable(I2Cx);
	
	if (ADDR_Length)//两字节地址
	{
        i2c_data_transmit(I2Cx, (uint8)((start_Addr & 0xFF00) >> 8));    
        ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
        if (E_NOT_OK == ret)
        {
            goto I2C_READ_NBYTES_END;
        }
        i2c_data_transmit(I2Cx, (uint8)(start_Addr & 0x00FF)); 
    }
	else
	{
		i2c_data_transmit(I2Cx, start_Addr);
	}
	ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }

    i2c_data_transmit(I2Cx, number_Bytes-1);
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }

    i2c_start_on_bus(I2Cx);
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_SBSEND, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }
	
	i2c_master_addressing(I2Cx, driver_Addr,  I2C_RECEIVER);
	
    
	if (number_Bytes < 3u)
	{
        i2c_ack_config(I2Cx,I2C_ACK_DISABLE);
    }
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_ADDSEND, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_READ_NBYTES_END;
    }

    /* clear the ADDSEND bit */
    i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND);
  	if (1u == number_Bytes)
	{
        i2c_stop_on_bus(I2Cx);
    }
    while (number_Bytes && rcvTimeout != 0)
    {
        if (3u == number_Bytes)
        {
            /* wait until BTC bit is set */
            ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
            if (E_NOT_OK == ret)
            {
                goto I2C_READ_NBYTES_END;
            }

            /* disable acknowledge */
            i2c_ack_config(I2Cx,I2C_ACK_DISABLE);
        }
        
        if (2u == number_Bytes)
        {
            /* wait until BTC bit is set */
            ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
            if (E_NOT_OK == ret)
            {
                goto I2C_READ_NBYTES_END;
            }
      
            /* send a stop condition to I2C bus */
            i2c_stop_on_bus(I2Cx);
            timeout = I2C_SHORT_TIMEOUT;
            while (0 != (I2C_CTL0(I2Cx) & 0x0200u))
            {
                timeout--;
                if (0 == timeout)
                {
                    I2C_Resume(I2Cx, I2C_LONG_TIMEOUT);
                    ret = E_NOT_OK;
                    goto I2C_READ_NBYTES_END;
                }
            }
        }
    
        /* wait until the RBNE bit is set and clear it */
        if (i2c_flag_get(I2Cx, I2C_FLAG_RBNE))
        {
            /* read a byte from the EEPROM */
            *read_Buffer = i2c_data_receive(I2Cx);

            /* point to the next location where the byte read will be saved */
            read_Buffer++; 

            /* decrement the read bytes counter */
            number_Bytes--;
        }
        rcvTimeout--;
    }
    
    timeout = I2C_SHORT_TIMEOUT;
    while (0 != (I2C_CTL0(I2Cx) & 0x0200u))
    {
        timeout--;
        if (0 == timeout)
        {
            I2C_Resume(I2Cx, I2C_LONG_TIMEOUT);
            ret = E_NOT_OK;
            goto I2C_READ_NBYTES_END;
        }
    }
  
    /* enable acknowledge */
    i2c_ack_config(I2Cx,I2C_ACK_ENABLE);

    i2c_ackpos_config(I2Cx,I2C_ACKPOS_CURRENT);

I2C_READ_NBYTES_END:
    return ret;
}

/*
    \brief      I2Cx Write NBytes 
    \param[in]  i2c_periph  : I2Cx(x=0,1)
    \param[in]  addr        : slave address   
    \param[in]  start_Addr  : reg
    \param[in]  number_Bytes: number to Write
    \param[in]  ADDR_Length : number of the addr
*/
Std_ReturnType I2C_Write_NBytes(uint32 I2Cx,uint8 driver_Addr, uint16 start_Addr, uint8 number_Bytes, uint8 *write_Buffer,uint8 ADDR_Length)
{
    uint32 timeout;
    Std_ReturnType ret = E_OK;
    
    i2c_ack_config(I2Cx,I2C_ACK_ENABLE);
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_I2CBSY, RESET);
    if (E_NOT_OK == ret)
    {
        goto I2C_WRITE_NBYTES_END;
    }

	i2c_start_on_bus(I2Cx);
	ret = I2C_WaitFlag(I2Cx, I2C_FLAG_SBSEND, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_WRITE_NBYTES_END;
    }

    i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER);
	ret = I2C_WaitFlag(I2Cx, I2C_FLAG_ADDSEND, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_WRITE_NBYTES_END;
    }
	
    i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND);
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_TBE, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_WRITE_NBYTES_END;
    }

    i2c_enable(I2Cx);
	if (ADDR_Length)//两字节地址
	{
        i2c_data_transmit(I2Cx, (uint8)((start_Addr & 0xFF00) >> 8));    
        ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
        if (E_NOT_OK == ret)
        {
            goto I2C_WRITE_NBYTES_END;
        }
        i2c_data_transmit(I2Cx, (uint8)(start_Addr & 0x00FF)); 
    }
	else
	{
		i2c_data_transmit(I2Cx, start_Addr);
	}
    
    ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
    if (E_NOT_OK == ret)
    {
        goto I2C_WRITE_NBYTES_END;
    }

    while (number_Bytes)
    {
        i2c_data_transmit(I2Cx, *write_Buffer); 
        ret = I2C_WaitFlag(I2Cx, I2C_FLAG_BTC, SET);
        if (E_NOT_OK == ret)
        {
            goto I2C_WRITE_NBYTES_END;
        }

        /* point to the next location where the byte read will be saved */
        write_Buffer++; 

        /* decrement the read bytes counter */
        number_Bytes--;
    } 

    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(I2Cx);
    
    timeout = I2C_SHORT_TIMEOUT;
    while (0 != (I2C_CTL0(I2Cx) & 0x0200u))
    {
        timeout--;
        if (0 == timeout)
        {
            I2C_Resume(I2Cx, I2C_LONG_TIMEOUT);
            ret = E_NOT_OK;
            goto I2C_WRITE_NBYTES_END;
        }
    }
  
    i2c_ack_config(I2Cx,I2C_ACK_ENABLE);
    
I2C_WRITE_NBYTES_END:
    return ret;
}

/***********************************************************************************************************************
**                                           Private Function Definitions                                             **
***********************************************************************************************************************/
static void I2C_Delay(uint32 i)
{
    while (i--);
}

static void I2C_Resume(uint32 I2Cx, uint32 Timeout)
{
    uint32 GPIO_SDA;
    uint32 GPIO_SCL;
    uint32 AFE1_SDA;
    uint32 AFE1_SCL;
    uint32 AFE2_SDA;
    uint32 AFE2_SCL;

    GPIO_SCL=GPIOB;
    GPIO_SDA=GPIOB;
    AFE1_SCL=GPIO_PIN_6;
    AFE1_SDA=GPIO_PIN_7;
    AFE2_SCL=GPIO_PIN_10;
    AFE2_SDA=GPIO_PIN_11;
    
    if (I2Cx == I2C0)
    {
        do{
            gpio_bit_reset(GPIO_SCL, AFE1_SCL);
            I2C_Delay(20);
            gpio_bit_reset(GPIO_SDA, AFE1_SDA);
            I2C_Delay(20);
            gpio_bit_set(GPIO_SCL, AFE1_SCL);
            I2C_Delay(20);
            gpio_bit_set(GPIO_SDA, AFE1_SDA);
            I2C_Delay(20);	

            Timeout--;
            if (0 == Timeout) return;
        } while ((!gpio_input_bit_get(GPIO_SDA, AFE1_SDA)) & (!gpio_input_bit_get(GPIO_SCL, AFE1_SCL)));
    }
    else if (I2Cx == I2C1)
    {
        do{
            gpio_bit_reset(GPIO_SCL, AFE2_SCL);
            I2C_Delay(20);
            gpio_bit_reset(GPIO_SDA, AFE2_SDA);
            I2C_Delay(20);
            gpio_bit_set(GPIO_SCL, AFE2_SCL);
            I2C_Delay(20);
            gpio_bit_set(GPIO_SDA, AFE2_SDA);
            I2C_Delay(20);	
      
            Timeout--;
            if (0 == Timeout) return;

        } while ((!gpio_input_bit_get(GPIO_SDA, AFE2_SDA)) & (!gpio_input_bit_get(GPIO_SCL, AFE2_SCL)));
    }
    
    I2C_Init(I2Cx);
}

static void I2C_Init(uint32 I2Cx)
{  	
    uint32 GPIO_SDA;
    uint32 GPIO_SCL;
    uint32 AFE1_SDA;
    uint32 AFE1_SCL;
    uint32 AFE2_SDA;
    uint32 AFE2_SCL;
    
    if (I2C0 == I2Cx)
    {
        rcu_periph_reset_enable(RCU_I2C0RST);
        rcu_periph_reset_disable(RCU_I2C0RST);
        /* enable GPIOB clock */
        rcu_periph_clock_enable(RCU_GPIOB);
        /* enable I2C0 clock */
        rcu_periph_clock_enable(RCU_I2C0);
        GPIO_SCL=GPIOB;
        AFE1_SCL=GPIO_PIN_6;
        GPIO_SDA=GPIOB;
        AFE1_SDA=GPIO_PIN_7;
        /* connect PB6 to I2C0_SCL */
        gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, AFE1_SCL);
        /* connect PB7 to I2C0_SDA */
        gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, AFE1_SDA);
    }
    else if (I2C1 == I2Cx)
    {
        rcu_periph_reset_enable(RCU_I2C1RST);
        rcu_periph_reset_disable(RCU_I2C1RST);
        /* enable GPIOB clock */
        rcu_periph_clock_enable(RCU_GPIOB);
        /* enable I2C0 clock */
        rcu_periph_clock_enable(RCU_I2C1);
        GPIO_SCL=GPIOB;
        AFE2_SCL=GPIO_PIN_10;
        GPIO_SDA=GPIOB;
        AFE2_SDA=GPIO_PIN_11;
        /* connect PB6 to I2C0_SCL */
        gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, AFE2_SCL);
        /* connect PB7 to I2C0_SDA */
        gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, AFE2_SDA);
    }
    else
    {
        /*do not support IIC*/
    }
	
    if ((I2C0 == I2Cx) || (I2C1 == I2Cx))
    {
        i2c_clock_config(I2Cx, 95000, I2C_DTCY_2);
        /* I2C address configure */
        i2c_mode_addr_config(I2Cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x0);
        /* enable acknowledge */
        i2c_ack_config(I2Cx, I2C_ACK_ENABLE);
        /* enable I2Cx */
        i2c_enable(I2Cx);
    }
}

static Std_ReturnType I2C_WaitFlag(uint32 i2c_periph, i2c_flag_enum flag, FlagStatus matchFlag)
{
    uint32 timeout = I2C_SHORT_TIMEOUT;
    FlagStatus getFlag;
    Std_ReturnType ret = E_OK;
    
    getFlag = i2c_flag_get(i2c_periph, flag);
    while (matchFlag != getFlag)
    {
        timeout--;
        if (0 == timeout)
        {
            I2C_Resume(i2c_periph, I2C_LONG_TIMEOUT);
            ret = E_NOT_OK;
            break;
        }
        getFlag = i2c_flag_get(i2c_periph, flag);
    }
    
    return ret;
}

/***********************************************************************************************************************
**                                                  General Notes                                                     **
***********************************************************************************************************************/

